﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Safe_Driving.EasyCalendar.Model
{
    [Serializable]
    public abstract class BindableObject : INotifyPropertyChanged
    {
        #region Data

        private static readonly Dictionary<string, PropertyChangedEventArgs> eventArgCache;
        private const string ERROR_MSG = "{0} is not a public property of {1}";
        private static readonly object syncLock = new object();

        #endregion

        #region Constructors

        static BindableObject()
        {
            eventArgCache = new Dictionary<string, PropertyChangedEventArgs>();
        }

        protected BindableObject()
        {
        }

        #endregion

        #region Public Members

        [field: NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        public static PropertyChangedEventArgs GetPropertyChangedEventArgs(string propertyName)
        {
            if (String.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentException("propertyName cannot be null or empty.");
            }

            PropertyChangedEventArgs args;
            lock (BindableObject.syncLock)
            {
                if (!eventArgCache.TryGetValue(propertyName, out args))
                {
                    eventArgCache.Add(propertyName, args = new PropertyChangedEventArgs(propertyName));
                }
            }

            return args;
        }

        #endregion

        #region Protected Members


        protected virtual void AfterPropertyChanged(string propertyName)
        {
        }

        protected void RaisePropertyChanged(string propertyName)
        {
            this.VerifyProperty(propertyName);

            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                // Get the cached event args.
                PropertyChangedEventArgs args =
                    GetPropertyChangedEventArgs(propertyName);

                // Raise the PropertyChanged event.
                handler(this, args);
            }

            this.AfterPropertyChanged(propertyName);
        }

        #endregion

        #region Private Helpers

        [Conditional("DEBUG")]
        private void VerifyProperty(string propertyName)
        {
            bool propertyExists = TypeDescriptor.GetProperties(this).Find(propertyName, false) != null;
            if (!propertyExists)
            {
                string msg = string.Format(
                    ERROR_MSG,
                    propertyName,
                    this.GetType().FullName);

                Debug.Fail(msg);
            }
        }

        #endregion
    }
}
